/*
 * =====================================================================================
 *
 *       Filename:  check_skelbdb.c
 *
 *    Description:  unit test for tcskelbdb.c
 *
 *        Version:  1.0
 *        Created:  02/16/2010 22:06:06
 *       Revision:  $Revision: 49 $
 *       Compiler:  gcc
 *
 *         Author:  Riceball LEE(riceball.lee@gmail.com) 
 *
 * =====================================================================================
 */

#include <stdlib.h>
#include <string.h>
#include <stdarg.h> //variable-length arguments macro in it.
#include <embUnit/embUnit.h>
#include <tcadb.h>
#include <tcbdb.h>
#include "../tcskelbdb.h"

#define STDBITVOID    "9999\0"
#define STDBITREINDEX "10000"
//#define DBFILE "./test.tcb#dbgfd=2"
#define DBFILE "./test.tcb"
static int tcadbindexvsiz2(TCADB *aDB, const char *aKey);
static uint64_t tcadbGetIndexNum(TCADB *aDB);
static uint64_t tcadbGetConfigNum(TCADB *aDB);
static TCXSTR *getIndexName(const char *aKey, const char *aField, const char *aValue);

static void _test_get(const char *aKey, const char *aExceptedValue);
static void _test_index_get(const char *aKey, const char *aField, const char *aValue, const char *aExceptedValue);
static void _test_add(char *aKey, char *aValue);
static void _test_del(char *aKey);
static void _test_setindex(char *aFieldName, char *aFieldOpt);
static void _test_removeindex(char *aFieldName);
static void _test_get(const char *aKey, const char *aExceptedValue);
static TCLIST *_test_misc(const char *aCmd, const TCLIST *aParams, const bool aExpected);
static void _test_misc_get(const char *aKey, const char *aExpectedValue, const bool aExpected);
static void _test_misc_del(const char *aKey, const bool aExpected);
static void _test_misc_reindex(const char *aFieldName, const bool aExpected);

static void test_clearDB(void);
static void test_add(void);
static void test_forbidden_add(void);
static void test_delete(void);
static void test_setindex(void);
static void test_removeindex(void);
static void test_misc_delete(void);
static void test_misc_reindex(void);
static void test_trans(void);

TCADB *CreateDB(void) {
  TCADB *vResult = tcadbnew();
  return vResult;
}

TCADB *GDB;

static void setup (void)
{
  GDB = CreateDB();
  TEST_ASSERT_MESSAGE(GDB != 0, "create ADB failed.");
  TEST_ASSERT_MESSAGE(tcADBSetSkelBDB(GDB), "set SkelBDB failed.");
  TEST_ASSERT_MESSAGE(tcadbopen(GDB, DBFILE), "open ./test/tcb db failed");
#if defined DEBUG
  //fprintf(stderr, "%s\n", "CreateDB OK");
#endif
}

static void teardown (void)
{
  tcadbdel(GDB);
}

//the last argument MUST be a NULL
static TCLIST *_test_misc(const char *aCmd, const TCLIST *aParams, const bool aExpected) {
  //#define CHECK_FORMAT(i, j) __attribute__((format(printf, i, j)))
  //int log_fatal(const char * fmt, ...) CHECK_FORMAT(2, 3);
  //va_list argp;
  //TCLIST * vParams = tclistnew();
//  char *para;
//  va_start(argp, aCmd); //point to the last determined argument.
//  do { //this will raise segment fatal error on Mac OSX.
//    para = va_arg(argp,char *);
//    if (para && strcmp(para, "")) {
//      fprintf(stderr, "arg=%s\n", para);
//      tclistpush2(vParams, para); 
//    }
//  } while (para && strcmp(para, "") != 0);
//  va_end(argp);
  TCLIST *vResult = tcadbmisc(GDB, aCmd, aParams);
  TEST_ASSERT_MESSAGE((vResult != NULL) == aExpected, "misc command result is not expected.");

  //tclistdel(vParams);
  return vResult;
}

static void _test_misc_get(const char *aKey, const char *aExpectedValue, const bool aExpected) {
  TCLIST * vParams = tclistnew();
  tclistpush2(vParams, aKey); 
  TCLIST *vValue = _test_misc("get", vParams, true);
  tclistdel(vParams);
  if (aExpected) {
    TEST_ASSERT_MESSAGE(vValue != NULL, "not found the key");
    TEST_ASSERT_MESSAGE(tclistnum(vValue) == 1, "the return list count error");
    const char *vbuf;
    int vsiz;
    TCLISTVAL(vbuf, vValue, 0, vsiz);
    TEST_ASSERT_EQUAL_STRING(aExpectedValue, vbuf);
    tclistdel(vValue);
  }
  else {
    TEST_ASSERT_MESSAGE(vValue == NULL, "I have found the key, but it's impossible.");
  }
}

static void _test_misc_del(const char *aKey, const bool aExpected) {
  TCLIST * vParams = tclistnew();
  tclistpush2(vParams, aKey); 
  TCLIST *vValue = _test_misc("out", vParams, aExpected);
  tclistdel(vParams);
  if (aExpected) {
    TEST_ASSERT_MESSAGE(vValue != NULL, "misc delete the key failed");
    tclistdel(vValue);
    TEST_ASSERT_MESSAGE(tcadbvsiz2(GDB, aKey) < 0, "misc delete the key failed. It still exists in DB.");  
  }
  else {
    TEST_ASSERT_MESSAGE(vValue == NULL, "misc delete the key successful, but it's not expected.");
  }
}

static void _test_get(const char *aKey, const char *aExceptedValue) {
  char *vValue = tcadbget2(GDB, aKey);  
  TEST_ASSERT_EQUAL_STRING(aExceptedValue, vValue);
  free(vValue);
}

//use tcxstrdel to free.
static TCXSTR *getIndexName(const char *aKey, const char *aField, const char *aValue) {
  TCXSTR *vResult = tcxstrnew3(MAXKEYLEN+1);
  tcxstrcat(vResult, IDXKEY, strlen(IDXKEY));
  tcxstrcat2(vResult, aField);
  tcxstrcat2(vResult, "/");
  tcxstrcat2(vResult, aValue);
  tcxstrcat2(vResult, "/");
  tcxstrcat2(vResult, aKey);
  return vResult;
}

static void _test_index_get(const char *aKey, const char *aField, const char *aValue, const char *aExceptedValue) {
//  char vIdxName[MAXKEYLEN+1];
//  strcpy(vIdxName, IDXKEY);
//  strcat(vIdxName, aField);
//  strcat(vIdxName, "/");
//  strcat(vIdxName, aValue);
//  strcat(vIdxName, "/");
//  strcat(vIdxName, aKey);
  TCXSTR *vIdxName = getIndexName(aKey, aField, aValue);
  TCLIST * vParams = tclistnew3(vIdxName->ptr, NULL);
  tcxstrdel(vIdxName);
  //  tclistpush2(vParams, aFieldName);
  //  tclistpush2(vParams, STDBITREINDEX);
  printf("test_getindex:%s\n", vIdxName->ptr);
  TCLIST *vValue = _test_misc("getindex", vParams, true);
  tclistdel(vParams);
  TEST_ASSERT_MESSAGE(vValue != NULL, "getindex failed:return TLIST is null");
  TEST_ASSERT_MESSAGE(tclistnum(vValue) > 0, "getindex failed:return TLIST count is 0");
  const char *vbuf;
  int vsiz;
  TCLISTVAL(vbuf, vValue, 0, vsiz);
  TEST_ASSERT_EQUAL_STRING(aExceptedValue, vbuf);
  if(vValue) tclistdel(vValue);
}

static void _test_add(char *aKey, char *aValue) {
  TEST_ASSERT_MESSAGE(tcadbput2(GDB, aKey, aValue), "add the key/value failed.");
  _test_get(aKey, aValue);
  _test_misc_get(aKey, aValue, true);
}

static void _test_del(char *aKey) {
  TEST_ASSERT_MESSAGE(tcadbout2(GDB, aKey), "delete the key failed.");
  TEST_ASSERT_MESSAGE(tcadbvsiz2(GDB, aKey) < 0, "delete the key failed. It still exists in DB.");  
}

static void _test_removeindex(char *aFieldName){
  TCLIST *vResults;
  char vIdxName[MAXKEYLEN+1];
  strcpy(vIdxName, IDXCONFIGKEY);
  strcat(vIdxName, aFieldName);
  //fprintf(stderr, "_test_removeIndex:%s\n", vIdxName);
  TEST_ASSERT_MESSAGE(GDB != NULL, "GDB is NULL");
  TEST_ASSERT_MESSAGE(tcDBConfigGetValueSize(((ADBSKEL*) GDB->skel)->opq, vIdxName, strlen(vIdxName)) >= 0, "removeindex the field is not indexed.");  
  
  //fprintf(stderr, "_test_removeIndex:%s\n", "make params before");
  //fprintf(stderr, "begin assign the parameter %s\n", aFieldName);
  //char *vIndexOpt = "9999";
  //this tclistnew3 will report error sometime: Segmentation fault
  //TCLIST *vParams = tclistnew3(aFieldName, STDBITVOID, "ddd", "asas");
  TCLIST *vParams = tclistnew();
  tclistpush2(vParams, aFieldName);
  tclistpush2(vParams, STDBITVOID);
  TEST_ASSERT_MESSAGE(vParams != NULL, "the parameter is NULL.");  
  //fprintf(stderr, "begin assign the parameter %d\n", tclistnum(vParams));
  TEST_ASSERT_MESSAGE(tclistnum(vParams) == 2, "the assigned parameter count error.");  
  

  //fprintf(stderr, "_test_removeIndex:%s\n", aFieldName);

  vResults = tcadbmisc(GDB, "setindex", vParams);
  //fprintf(stderr, "removeIndx:%s\n", "removed");
  //if (vResults == NULL) return;
  TEST_ASSERT_MESSAGE(vResults != NULL, "removeindex return list is null error.");
  TEST_ASSERT_MESSAGE(tclistnum(vResults) == 0, "removeindex return list count error.");
  tclistdel(vParams);
  tclistdel(vResults);
  TEST_ASSERT_MESSAGE(tcDBConfigGetValueSize(((ADBSKEL*) GDB->skel)->opq, vIdxName, strlen(vIdxName)) < 0, "removeindex failed. It still exists in index configuration.");  

  TBTreeDatabase *vDB = ((ADBSKEL*) GDB->skel)->opq;
  TCBDB *vIndexDB = vDB->IndexDB;
  strcpy(vIdxName, IDXKEY);
  strcat(vIdxName, aFieldName);
  strcat(vIdxName, "/");
  //fprintf(stderr, "try search index:%s\n", vIdxName);
  vResults = tcbdbfwmkeys2(vIndexDB, vIdxName, 1);
  //fprintf(stderr, "try get index:%s\n", vIdxName);
  TEST_ASSERT_MESSAGE(tclistnum(vResults) == 0, "removeindex failed. It still exists index.");  
  tclistdel(vResults);
}

static uint64_t tcadbGetIndexNum(TCADB *aDB){
  return tcDBGetIndexNum(((ADBSKEL*) GDB->skel)->opq);
}

static uint64_t tcadbGetConfigNum(TCADB *aDB){
  return tcDBGetConfigNum(((ADBSKEL*) GDB->skel)->opq);
}

static void _test_setindex(char *aFieldName, char *aFieldOpt) {
  TCLIST *vParams = tclistnew();
  tclistpush2(vParams, aFieldName);
  tclistpush2(vParams, aFieldOpt);
  
  TCLIST *vResults;
  char vIdxName[MAXKEYLEN+1];
  
  vResults = tcadbmisc(GDB, "setindex", vParams);
  TEST_ASSERT_MESSAGE(vResults != NULL, "setindex return list is null error.");
  TEST_ASSERT_MESSAGE(tclistnum(vResults) == 0, "setindex return list count error.");
  tclistdel(vParams);
  tclistdel(vResults);
  strcpy(vIdxName, IDXCONFIGKEY);
  strcat(vIdxName, aFieldName);
  TEST_ASSERT_MESSAGE(tcDBConfigGetValueSize(((ADBSKEL*) GDB->skel)->opq, vIdxName, strlen(vIdxName)) >= 0, "setindex can not put the index configuration info correctly.");
  //TEST_ASSERT_MESSAGE(tcadbout2(GDB, vIdxName), "(setindex)delete the index config failed.");
}

static void _test_misc_reindex(const char *aFieldName, const bool aExpected) {
  TCLIST * vParams = tclistnew3(aFieldName, STDBITREINDEX, NULL);
  //  tclistpush2(vParams, aFieldName);
  //  tclistpush2(vParams, STDBITREINDEX);
  TCLIST *vValue = _test_misc("setindex", vParams, aExpected);
  tclistdel(vParams);
  TEST_ASSERT_MESSAGE((vValue != NULL) == aExpected, "reindex result is not expected.");
  tclistdel(vValue);
}

static void test_misc_reindex(void) {
  test_add();
  _test_add("myword3", "{\"so\":1112,\"key\":\"hi3\",\"goodkey\":true,\"中文Key\":\"Good世界你好哟。\"}");
  TEST_ASSERT_MESSAGE(tcadbGetIndexNum(GDB) == 3+3+3, "add myword3 the key/value, but the index number is error.");
  TEST_ASSERT_MESSAGE(tcadbrnum(GDB) == 3, "add myword3 the key/value, but the record number is error.");
  _test_index_get("myword3","key","\"hi3\"","myword3");
  
  _test_index_get("myword3","goodkey", "true", "myword3");
  
  _test_index_get("myword3","中文Key","\"Good世界你好哟。\"", "myword3");

  _test_setindex("so", "0");
  _test_misc_reindex("so", true);
  TEST_ASSERT_MESSAGE(tcadbGetIndexNum(GDB) == 3+3+3+3, "reindex so, but the index number is error.");
  //TEST_ASSERT_MESSAGE(tcadbrnum(GDB) == 3+1+3+1+3+4+3+1, "reindex so, but the record number is error.");  
}

static void test_clearDB(void) {
  TEST_ASSERT_MESSAGE(GDB != NULL, "the GDB is null");
  TEST_ASSERT_MESSAGE(tcadbvanish(GDB), "empty the DB failed.");
  TEST_ASSERT_MESSAGE(tcadbrnum(GDB) == 0, "empty the DB, but the DB record num is not 0");
  TEST_ASSERT_MESSAGE(tcadbGetIndexNum(GDB) == 0, "empty the DB, but the DB Index record num is not 0");
  TEST_ASSERT_MESSAGE(tcadbGetConfigNum(GDB) == 0, "empty the DB, but the DB config record num is not 0");
  //TEST_ASSERT_MESSAGE(tcadbsize(GDB) == 0, "empty the DB, but the DB size is not 0");
}

static int tcadbindexvsiz2(TCADB *aDB, const char *aKey) {
  void *vDB = aDB->skel;
  vDB = ((ADBSKEL*) vDB)->opq;
  vDB = ((TBTreeDatabase*) vDB)->IndexDB;
  return tcbdbvsiz2((TCBDB*)vDB, aKey);
}

static void test_delete(void) {
  test_add();
  TEST_ASSERT_MESSAGE(tcadbout2(GDB, "DfkdsjFH") == false, "delete the unexists key should be failed, but successful.");
  _test_del("myword1");
  TEST_ASSERT_MESSAGE(tcadbvsiz2(GDB, "myword1") == -1, "delete the myword1 key, but still can get the value.");

  TCXSTR *vIdxName = getIndexName("myword1", "key", "\"hi\"");
  TEST_ASSERT_MESSAGE(tcadbindexvsiz2(GDB, vIdxName->ptr) == -1, "delete the myword1 key, but still can get the field 'key' index.");
  tcxstrdel(vIdxName);

  vIdxName = getIndexName("myword1", "goodkey", "true");
  TEST_ASSERT_MESSAGE(tcadbindexvsiz2(GDB, vIdxName->ptr) == -1, "delete the myword1 key, but still can get the field 'goodkey' index.");
  tcxstrdel(vIdxName);

  vIdxName = getIndexName("myword1", "中文Key", "\"世界你好\"");
  TEST_ASSERT_MESSAGE(tcadbindexvsiz2(GDB, vIdxName->ptr) == -1, "delete the myword1 key, but still can get the field '中文Key' index.");
  tcxstrdel(vIdxName);

  _test_del("myword");
  TEST_ASSERT_MESSAGE(tcadbindexvsiz2(GDB, "myword") == -1, "delete the myword key, but still can get the value.");

  vIdxName = getIndexName("myword", "key", "\"hi\"");
  TEST_ASSERT_MESSAGE(tcadbindexvsiz2(GDB, vIdxName->ptr) == -1, "delete the myword key, but still can get the field 'key' index.");
  tcxstrdel(vIdxName);

  vIdxName = getIndexName("myword", "goodkey", "true");
  TEST_ASSERT_MESSAGE(tcadbindexvsiz2(GDB, vIdxName->ptr) == -1, "delete the myword key, but still can get the field 'goodkey' index.");
  tcxstrdel(vIdxName);

  vIdxName = getIndexName("myword", "中文Key", "\"世界你好\"");
  TEST_ASSERT_MESSAGE(tcadbindexvsiz2(GDB, vIdxName->ptr) == -1, "delete the myword key, but still can get the field '中文Key' index.");
  tcxstrdel(vIdxName);
}

static void test_misc_delete(void) {
  test_add();
  _test_misc_del("DfkdsjFH", false);
  //TEST_ASSERT_MESSAGE( == false, "delete the unexists key should be failed, but successful.");
  _test_misc_del("myword1", true);
  TEST_ASSERT_MESSAGE(tcadbvsiz2(GDB, "myword1") == -1, "delete the myword1 key, but still can get the value.");
  
  TCXSTR *vIdxName = getIndexName("myword1", "key", "\"hi\"");
  TEST_ASSERT_MESSAGE(tcadbindexvsiz2(GDB, vIdxName->ptr) == -1, "delete the myword1 key, but still can get the field 'key' index.");
  tcxstrdel(vIdxName);
  
  vIdxName = getIndexName("myword1", "goodkey", "true");
  TEST_ASSERT_MESSAGE(tcadbindexvsiz2(GDB, vIdxName->ptr) == -1, "delete the myword1 key, but still can get the field 'goodkey' index.");
  tcxstrdel(vIdxName);
  
  vIdxName = getIndexName("myword1", "中文Key", "\"世界你好\"");
  TEST_ASSERT_MESSAGE(tcadbindexvsiz2(GDB, vIdxName->ptr) == -1, "delete the myword1 key, but still can get the field '中文Key' index.");
  tcxstrdel(vIdxName);
  
  _test_del("myword");
  TEST_ASSERT_MESSAGE(tcadbindexvsiz2(GDB, "myword") == -1, "delete the myword key, but still can get the value.");
  
  vIdxName = getIndexName("myword", "key", "\"hi\"");
  TEST_ASSERT_MESSAGE(tcadbindexvsiz2(GDB, vIdxName->ptr) == -1, "delete the myword key, but still can get the field 'key' index.");
  tcxstrdel(vIdxName);
  
  vIdxName = getIndexName("myword", "goodkey", "true");
  TEST_ASSERT_MESSAGE(tcadbindexvsiz2(GDB, vIdxName->ptr) == -1, "delete the myword key, but still can get the field 'goodkey' index.");
  tcxstrdel(vIdxName);
  
  vIdxName = getIndexName("myword", "中文Key", "\"世界你好\"");
  TEST_ASSERT_MESSAGE(tcadbindexvsiz2(GDB, vIdxName->ptr) == -1, "delete the myword key, but still can get the field '中文Key' index.");
  tcxstrdel(vIdxName);
}

static void test_forbidden_add(void) {
  TEST_ASSERT_MESSAGE(GDB != NULL, "the GDB is null");
  test_clearDB();
  tcadbput2(GDB, "_myword", "{\"so\":12,\"key\":\"hi\",\"goodkey\":true,\"中文Key\":\"世界你好\"}");
  TEST_ASSERT_MESSAGE(tcadbrnum(GDB) == 0, "the count should be 0, but.");
  tcadbput2(GDB, "/myword", "{\"so\":12,\"key\":\"hi\",\"goodkey\":true,\"中文Key\":\"世界你好\"}");
  TEST_ASSERT_MESSAGE(tcadbrnum(GDB) == 0, "the count should be 0, but.");
  tcadbput2(GDB, "|myword", "{\"so\":12,\"key\":\"hi\",\"goodkey\":true,\"中文Key\":\"世界你好\"}");
  TEST_ASSERT_MESSAGE(tcadbrnum(GDB) == 0, "the count should be 0, but.");
  tcadbput2(GDB, "\\myword", "{\"so\":12,\"key\":\"hi\",\"goodkey\":true,\"中文Key\":\"世界你好\"}");
  TEST_ASSERT_MESSAGE(tcadbrnum(GDB) == 0, "the count should be 0, but.");
  tcadbput2(GDB, "\"myword", "{\"so\":12,\"key\":\"hi\",\"goodkey\":true,\"中文Key\":\"世界你好\"}");
  TEST_ASSERT_MESSAGE(tcadbrnum(GDB) == 0, "the count should be 0, but.");
  tcadbput2(GDB, ".myword", "{\"so\":12,\"key\":\"hi\",\"goodkey\":true,\"中文Key\":\"世界你好\"}");
  TEST_ASSERT_MESSAGE(tcadbrnum(GDB) == 0, "the count should be 0, but.");
}

static void test_add(void) {
  //char vIdxName[MAXKEYLEN+1];

  TEST_ASSERT_MESSAGE(GDB != NULL, "the GDB is null");
  test_clearDB();
  //first add three index.
  _test_setindex("key", "0");
  _test_setindex("goodkey", "0");
  _test_setindex("中文Key", "0");

  _test_add("myword", "{\"so\":12,\"key\":\"hi\",\"goodkey\":true,\"中文Key\":\"世界你好\"}");
  TEST_ASSERT_MESSAGE(tcadbrnum(GDB) == 1, "add the key/value, but the record number is error.");
  _test_index_get("myword","key","\"hi\"","myword");
  
  _test_index_get("myword","goodkey", "true", "myword");
  
  _test_index_get("myword","中文Key","\"世界你好\"", "myword");
  
  //*[bug] The duplication index(FieldValue) not supported.
  _test_add("myword1", "{\"so\":122,\"key\":\"hi1\",\"goodkey\":true,\"中文Key\":\"世界你好\"}");
  TEST_ASSERT_MESSAGE(tcadbrnum(GDB) == 2, "add another the key/value, but the record number is error.");

  _test_index_get("myword1","key", "\"hi1\"", "myword1");
  
  _test_index_get("myword1","goodkey", "true", "myword1");

  _test_index_get("myword1","中文Key", "\"世界你好\"", "myword1");
}

static void test_removeindex(void)
{
  test_add();
  //fprintf(stderr, "before remove %s\n",""); 
  //fprintf(stderr, "before remove %d\n",tcadbrnum(GDB)); 
  _test_removeindex("key");
  //fprintf(stderr, "after %d\n",tcadbrnum(GDB)); 
  TEST_ASSERT_MESSAGE(tcadbGetIndexNum(GDB) == 4, "remove the key field index, but the record number is error.");
  _test_removeindex("goodkey");
  TEST_ASSERT_MESSAGE(tcadbGetIndexNum(GDB) == 2, "remove the goodkey field index, but the record number is error.");
  _test_removeindex("中文Key");
  TEST_ASSERT_MESSAGE(tcadbGetIndexNum(GDB) == 0, "remove the 中文Key field index, but the record number is error.");
}

static void test_setindex(void)
{
  //fprintf(stderr, "begin %s\n", __FUNCTION__);
  
  /* unit test code */
  //char *vFieldKey = "key";
  //TCLIST *vResults;
  //TCLIST *vParams = tclistnew3(vFieldKey, "0");

  TEST_ASSERT_MESSAGE(GDB != NULL, "the GDB is null");

  test_clearDB();
  _test_setindex("key", "0");
  _test_setindex("goodkey", "0");
  _test_setindex("中文Key", "0");

  //TEST_ASSERT_MESSAGE(tcadbvanish(GDB), "empty the DB failed.");
  //TEST_ASSERT_MESSAGE(tcadbrnum(GDB) == 0, "empty the DB, but the DB record num is not 0");

  //fprintf(stderr,"%s\n","1");
  //vResults = tcadbmisc(GDB, "setindex", vParams);
  //fprintf(stderr, "res:%d\n", vResults);
  //TEST_ASSERT_MESSAGE(vResults != NULL, "setindex return list is null error.");
  //fprintf(stderr, "rescout:%d\n", tclistnum(vResults));
  //TEST_ASSERT_MESSAGE(tclistnum(vResults) == 0, "setindex return list count error.");
  
  //tclistdel(vResults);
  //char vIdxName[MAXKEYLEN+1];
  //strcpy(vIdxName, IDXCONFIGKEY);
  //strcat(vIdxName, vFieldKey);
  //TEST_ASSERT_MESSAGE(tcadbvsiz2(GDB, vIdxName) >= 0, "setindex can not put the index configuration info correctly.");
  //TEST_ASSERT_MESSAGE(tcadbout2(GDB, vIdxName), "(setindex)delete the index config failed.");
}

static void test_trans(void){
  TEST_ASSERT_MESSAGE(GDB != NULL, "the GDB is null");
  
  test_clearDB();
  test_add();
  uint64_t count = tcadbrnum(GDB);
  tcadbtranbegin(GDB);
  _test_add("my", "{\"so\":11332,\"key\":\"hiiiii\",\"goodkey\":true,\"中文Key\":\"Sd世界你好\"}");
  tcadbtranabort(GDB);
  TEST_ASSERT_MESSAGE(tcadbrnum(GDB) == count, "the transaction is aborted, but the record is changed.");
  tcadbtranbegin(GDB);
  _test_add("my", "{\"so\":11332,\"key\":\"hiiiii\",\"goodkey\":true,\"中文Key\":\"Sd世界你好\"}");
  tcadbtrancommit(GDB);
  ++count;
  TEST_ASSERT_MESSAGE(tcadbrnum(GDB) == count, "the transaction is commit, but the record count is error.");
}

TestRef SkelBDB_tests( TestCaller *test )
{
	EMB_UNIT_TESTFIXTURES(fixtures) {
    new_TestFixture("test_misc_reindex",test_misc_reindex),
		new_TestFixture("test_clearDB",test_clearDB),
		new_TestFixture("test_Setindex",test_setindex),
		new_TestFixture("test_removeindex",test_removeindex),
    new_TestFixture("test_delete",test_delete),
    new_TestFixture("test_misc_delete",test_misc_delete),
    new_TestFixture("test_forbidden_add",test_forbidden_add),
    new_TestFixture("test_trans", test_trans),
		new_TestFixture("test_add",test_add),
	};
	EMB_UNIT_TESTCALLER(test,"SkelBDBTests",setup,teardown,fixtures);
  
	return (TestRef)test;
}
